#ifndef __BASE_HPP__
#define __BASE_HPP__
/////////////////////////////////////////////////
#include <vector>
#include <fstream>
#include <iostream>

using namespace std;

#define SPACE ' '
#define WALL 'W'
#define BOX 'B'
#define MAN 'P'
#define TARGET 'X'
#define BOX_T 'b' // 这两个是和目标点重合的情况
#define MAN_T 'p'

#define SPACE_OUT "  "
#define WALL_OUT "LL"
#define BOX_OUT "B "
#define MAN_OUT "O "
#define TARGET_OUT "X "
#define BOX_T_OUT "b "
#define MAN_T_OUT "o"

typedef struct Point2D
{
    int x;
    int y;

    bool operator==(const Point2D &other) const
    {
        return (x == other.x) && (y == other.y);
    }
    bool operator!=(const Point2D &other) const
    {
        return (x != other.x) || (y != other.y);
    }
} Point2D;

typedef struct _State
{
    vector<vector<bool>> map; // 这里存储地图(只包含墙)
    Point2D man;              // 人的位置
    vector<Point2D> box;      // 箱子的位置
    vector<Point2D> target;   // 目标点的位置
    int step;                 // 当前是第几步操作
} _State;

class MainProcess
{
public:
    _State state;

    MainProcess()
    {
    }

    /// @brief 用给定状态初始化程序
    /// @param state
    MainProcess(_State state)
    {
        this->state = state;
    }

    /// @brief 初始化程序
    /// @param state 用给定地图初始化
    MainProcess(string filepath)
    {
        openFile(filepath);
    }

    void openFile(string filepath)
    {
        state.step = 0;
        state.target.clear();
        state.box.clear();
        state.map.clear();

        if (filepath[0] == ' ' || filepath[0] == '"')
            filepath = filepath.substr(1);
        if (filepath[filepath.size() - 1] == ' ' || filepath[filepath.size() - 1] == '"')
            filepath.pop_back();

        ifstream file;
        file.open(filepath.c_str());

        if (!file.is_open())
            cerr << "Error on opening file: " << filepath << endl;

        int i = 0, j = 0;
        string line;
        while (getline(file, line))
        {
            vector<bool> l;
            for (int j = 0; j < line.size(); j++)
            {
                l.push_back(line[j] == WALL);
                if (line[j] != WALL)
                {
                    if (line[j] == MAN)
                        state.man = {j, i};
                    if (line[j] == BOX)
                        state.box.push_back({j, i});
                    if (line[j] == TARGET)
                        state.target.push_back({j, i});
                    if (line[j] == BOX_T)
                    {
                        state.box.push_back({j, i});
                        state.target.push_back({j, i});
                    }
                    if (line[j] == MAN_T)
                    {
                        state.man = {j, i};
                        state.target.push_back({j, i});
                    }
                }
            }
            state.map.push_back(l);
            i++;
        }
    }

    /// @brief 向指定方向移动
    /// @param c 移动方向，取值为 W A S D，分别代表 上 左 下 右
    /// @return 0:成功；1:被墙阻挡；2:被两个箱子阻挡；3:被箱子和墙阻挡；-1:输入错误
    int MoveToward(char c)
    {
        int dx = 0, dy = 0;
        switch (c)
        {
        case 'W':
            dy = -1;
            break;
        case 'A':
            dx = -1;
            break;
        case 'S':
            dy = 1;
            break;
        case 'D':
            dx = 1;
            break;
        default:
            return -1; // 输入错误
        }

        int newX = state.man.x + dx;
        int newY = state.man.y + dy;

        // Check for wall or out of bounds
        if (newX < 0 || newX >= state.map[0].size() || newY < 0 || newY >= state.map.size() || state.map[newY][newX])
            return 1; // 被墙阻挡

        // Check for box
        int boxIndex = -1;
        for (int i = 0; i < state.box.size(); i++)
        {
            Point2D box = state.box[i];
            if (box.x == newX && box.y == newY)
            {
                boxIndex = i;
                break;
            }
        }
        if (boxIndex != -1)
        {
            // Check if pushing the box would hit a wall or another box
            int newBoxX = newX + dx;
            int newBoxY = newY + dy;
            if (newBoxX < 0 || newBoxX >= state.map[0].size() || newBoxY < 0 || newBoxY >= state.map.size() || state.map[newBoxY][newBoxX])
                return 3; // 被箱子和墙阻挡
            for (Point2D box : state.box)
                if (newBoxX == box.x && newBoxY == box.y)
                    return 2; // 被两个箱子阻挡

            // Successfully pushed the box
            state.box[boxIndex].x = newBoxX;
            state.box[boxIndex].y = newBoxY;
        }

        // Move the man
        state.man.x = newX;
        state.man.y = newY;
        state.step++; // Increment step count

        return 0; // 成功
    }

    /// @brief 把当前的State写入指定文件
    /// @param filepath
    /// @return 0:成功；1:文件打开失败
    int writeFile(string filepath)
    {
        ofstream file;
        file.open(filepath.c_str(), ios::out);

        if (!file.is_open())
            return 1;

        string s = toString();
        file << s.c_str();

        file.close();
        return 0;
    }

    /// @brief 把当前场景转化为字符串
    string toString()
    {
        string s = "";
        for (int i = 0; i < state.map.size(); i++)
        {
            for (int j = 0; j < state.map[i].size(); j++)
            {
                if (state.map[i][j])
                    s += WALL;
                else
                {
                    bool flag_m = false, flag_b = false, flag_t = false;
                    if (state.man.x == j && state.man.y == i)
                        flag_m = true;
                    for (int k = 0; k < state.box.size(); k++)
                        if (state.box[k].x == j && state.box[k].y == i)
                        {
                            flag_b = true;
                            break;
                        }
                    for (int k = 0; k < state.target.size(); k++)
                        if (state.target[k].x == j && state.target[k].y == i)
                        {
                            flag_t = true;
                            break;
                        }

                    if (flag_m && !flag_b && !flag_t)
                        s += MAN;
                    if (!flag_m && flag_b && !flag_t)
                        s += BOX;
                    if (!flag_m && !flag_b && flag_t)
                        s += TARGET;
                    if (flag_m && !flag_b && flag_t)
                        s += MAN_T;
                    if (!flag_m && flag_b && flag_t)
                        s += BOX_T;
                    if (!flag_m && !flag_b && !flag_t)
                        s += SPACE;
                }
            }
            s += '\n';
        }
        return s;
    }

    /// @brief 把当前场景转化为字符串(输出类型)
    string toString2()
    {
        string s = "";
        for (int i = 0; i < state.map.size(); i++)
        {
            for (int j = 0; j < state.map[i].size(); j++)
            {
                if (state.map[i][j])
                    s += WALL_OUT;
                else
                {
                    bool flag_m = false, flag_b = false, flag_t = false;
                    if (state.man.x == j && state.man.y == i)
                        flag_m = true;
                    for (int k = 0; k < state.box.size(); k++)
                        if (state.box[k].x == j && state.box[k].y == i)
                        {
                            flag_b = true;
                            break;
                        }
                    for (int k = 0; k < state.target.size(); k++)
                        if (state.target[k].x == j && state.target[k].y == i)
                        {
                            flag_t = true;
                            break;
                        }

                    if (flag_m && !flag_b && !flag_t)
                        s += MAN_OUT;
                    if (!flag_m && flag_b && !flag_t)
                        s += BOX_OUT;
                    if (!flag_m && !flag_b && flag_t)
                        s += TARGET_OUT;
                    if (flag_m && !flag_b && flag_t)
                        s += MAN_T_OUT;
                    if (!flag_m && flag_b && flag_t)
                        s += BOX_T_OUT;
                    if (!flag_m && !flag_b && !flag_t)
                        s += SPACE_OUT;
                }
            }
            s += '\n';
        }
        return s;
    }

    /// @brief 检查当前状态是否已经达成目标
    bool check()
    {
        for (Point2D box : state.box)
        {
            bool flag = false;
            for (Point2D target : state.target)
                if (box == target)
                    flag = true;
            if (!flag)
                return false;
        }
        return true;
    }
};

///////////////////////////////////////////////////
#endif